#pragma once
#include <memory>
#include <list>
#include <map>
#include <Windows.h>
#include "Geometry.h"

class Actor;
class ActorComponent;

typedef unsigned int ActorId;
typedef unsigned int ComponentId;

const ActorId INVALID_ACTOR_ID = 0;
const ComponentId INVALID_COMPONENT_ID = 0;

typedef std::shared_ptr<Actor> StrongActorPtr;
typedef std::weak_ptr<Actor> WeakActorPtr;
typedef std::map<ActorId, StrongActorPtr> ActorMap;
typedef std::shared_ptr<ActorComponent> StrongActorComponentPtr;
typedef std::weak_ptr<ActorComponent> WeakActorComponentPtr;

template<class T>
struct SortBy_SharedPtr_Content
{
	bool operator()(const std::shared_ptr<T> &lhs, const std::shared_ptr<T> &rhs) const
	{ return *lhs < *rhs; }
};

class IScreenElement
{
public:
	virtual ~IScreenElement() { }

	virtual HRESULT VRestore() = 0;
	virtual HRESULT VRender() = 0;
	virtual void VUpdate(double deltaSecs) = 0;
	virtual int VGetZOrder() const = 0;
	virtual void VSetZOrder(int const zOrder) = 0;
	virtual bool VIsVisible() const = 0;
	virtual void VSetVisible(bool visible) = 0;

	virtual bool const operator <(IScreenElement const &other) { return VGetZOrder() < other.VGetZOrder(); }
};
typedef std::shared_ptr<IScreenElement> ScreenElementPtr;
typedef std::list<ScreenElementPtr> ScreenElementList;

class IGame
{
public:
	virtual ~IGame() { }

	virtual bool VPreload() = 0;
	virtual bool VInit() = 0;
	virtual bool VLoadGame(const char* levelRes) = 0;
	virtual void VUpdate(double deltaSecs) = 0;
	virtual void VRenderViews() = 0;
	virtual StrongActorPtr VGetActor(const ActorId id) = 0;
	virtual void VAddActor(StrongActorPtr pActor) = 0;
	virtual void VRemoveActor(ActorId id) = 0;
};

typedef unsigned int GameViewId;

enum GameViewType
{
	GameView_Human,
	GameView_Remote,
	GameView_AI,
	GameView_Recorder,
	GameView_Other
};

class IGameView
{
public:
	virtual ~IGameView() { }

	virtual HRESULT VRestore() = 0;
	virtual void VUpdate(double deltaSecs) = 0;
	virtual void VRender() = 0;
	virtual GameViewId VGetId() const = 0;
	virtual GameViewType VGetType() = 0;
	virtual void VAttach(GameViewId id, ActorId aid = 0) = 0;
};
typedef std::shared_ptr<IGameView> GameViewPtr;
typedef std::list<GameViewPtr> GameViewList;

class Scene;
class SceneNodeProperties;

class ISceneNode
{
public:
	virtual const SceneNodeProperties * const VGet() const=0;

	virtual void VSetTransform(const Mat4x4 *toWorld, const Mat4x4 *fromWorld=NULL)=0;

	virtual HRESULT VUpdate(Scene *pScene, double deltaSecs)=0;
	virtual HRESULT VRestore(Scene *pScene)=0;

	virtual HRESULT VPreRender(Scene *pScene)=0;
	virtual bool VIsVisible(Scene *pScene) const=0;
	virtual HRESULT VRender(Scene *pScene)=0;
	virtual HRESULT VRenderChildren(Scene *pScene)=0;
	virtual HRESULT VPostRender(Scene *pScene)=0;

	virtual bool VAddChild(std::shared_ptr<ISceneNode> kid)=0;
	virtual bool VRemoveChild(ActorId id)=0;
	//virtual HRESULT VOnLostDevice(Scene *pScene)=0;
	//virtual HRESULT VPick(Scene *pScene, RayCast *pRayCast)=0;

	virtual ~ISceneNode() { };
};

class Scene2D;
class SceneNode2DProperties;

class ISceneNode2D
{
public:
	virtual const SceneNode2DProperties* const VGet() const = 0;
	virtual void VSetTransform()=0;
	virtual void VSetSize(const Vec2& size)= 0;
	virtual void VSetPosition(const Vec2& pos) = 0;
	virtual void VSetOrientation(const double& ori) = 0;
	virtual void VUpdate(Scene2D* pScene, double deltaSecs) = 0;
	virtual HRESULT VRestore(Scene2D* pScene) = 0;
	virtual HRESULT VPreRender(Scene2D *pScene) = 0;
	virtual bool VIsVisible(Scene2D * pScene) = 0;
	virtual HRESULT VRender(Scene2D *pScene) = 0;
	virtual HRESULT VRenderChildren(Scene2D *pScene) = 0;
	virtual HRESULT VPostRender(Scene2D *pScene) = 0;
	virtual bool VAddChild(std::shared_ptr<ISceneNode2D> kid) = 0;
	virtual bool VRemoveChild(ActorId id) = 0;
	virtual HRESULT VPick(Scene2D *pScene, const Vec2& Position) = 0;

	virtual ~ISceneNode2D() { }
};

class IScriptManager
{
public:
	virtual ~IScriptManager() { }
	virtual bool VInit() = 0;
	virtual void VExecuteFile(const char* resource) = 0;
	virtual void VExecuteString(const char* str) = 0;
};
